package vn.bus.service;

import java.util.ArrayList;
import java.util.Hashtable;

import vn.bus.dto.ConnectionDTO;
import vn.bus.dto.LabelDTO;
//import vn.bus.dto.LabelDTO;
import vn.bus.dto.NearbyConnectionDTO;
import vn.bus.auxiliary.MinHeap;

;

public class STPService {

	MinHeap LLVTemp = new MinHeap();
	ArrayList<LabelDTO> LLVPer = new ArrayList<LabelDTO>();

	public Hashtable<String, ArrayList<ConnectionDTO>> loadNodeConns() {
		ConnectionService NodeConns = new ConnectionService();
		Hashtable<String, ArrayList<ConnectionDTO>> NodeConnections = new Hashtable<String, ArrayList<ConnectionDTO>>();
		NodeConnections = NodeConns.loadAllNodeConns();

		return NodeConnections;
	}

	public Hashtable<String, ArrayList<NearbyConnectionDTO>> loadNodeNearbyConns() {
		NearbyConnectionService NodeNearbyConns = new NearbyConnectionService();

		Hashtable<String, ArrayList<NearbyConnectionDTO>> NodeNearbyConnection = new Hashtable<String, ArrayList<NearbyConnectionDTO>>();
		NodeNearbyConnection = NodeNearbyConns.loadAllNodeNearbyConns();

		return NodeNearbyConnection;
	}

	// Shortest Path ===========================================================

	public ArrayList<LabelDTO> ShortestPath(String dep, String arr,
			ArrayList<String> priority, int minwalk, int maxwalk, int timedep) {
		// load NodeConnection
		Hashtable<String, ArrayList<ConnectionDTO>> NodeConnections = new Hashtable<String, ArrayList<ConnectionDTO>>();
		ConnectionService NodeConns = new ConnectionService();
		NodeConnections = NodeConns.loadAllNodeConns();
		// load NodeNearbyConnection
		Hashtable<String, ArrayList<NearbyConnectionDTO>> NodeNearbyConnection = new Hashtable<String, ArrayList<NearbyConnectionDTO>>();
		if (maxwalk > 0) {
			NearbyConnectionService NodeNearbyConns = new NearbyConnectionService();
			NodeNearbyConnection = NodeNearbyConns.loadAllNodeNearbyConns();
		}

		// algorithms
		int timeChangeRoute = 15*60;
		int velocityBus = 20; // velocity bus = 20km/h
		int velocityWalk = 5; // velocity walk = 20km/h
		boolean findShortPath = false;
		setLLVPer(dep, 0, 0, 0, "0", 0, 0);
		LabelDTO LVTCur = new LabelDTO();
		LVTCur.setS(dep);
		LVTCur.setT(0);
		LVTCur.setD(0);
		LVTCur.setP(0);
		LVTCur.setPrevS("0");
		LVTCur.setR(0);
		LVTCur.setDw(0);

		while (true) {
			// list label vertex temporary
			ArrayList<ConnectionDTO> dataNext = new ArrayList<ConnectionDTO>();
			dataNext = NodeConnections.get(LVTCur.getS());
			if (dataNext != null) {
				while (dataNext.size() > 0) {
					int timeNext = 0, priceNext = 0, distanceNext = 0;
					if(LVTCur.getR() != (dataNext.get(0)).getRoute()){
						priceNext = 4000;
						timeNext = timeChangeRoute;
					}
					priceNext = priceNext + LVTCur.getP();
					distanceNext = (dataNext.get(0)).getDistance() + LVTCur.getD();
					timeNext = timeNext + LVTCur.getT() 
							+ (3600*((dataNext.get(0)).getDistance())) / (velocityBus*1000);
					
					LabelDTO itemLLVTemp = new LabelDTO();
					
					itemLLVTemp.setS((dataNext.get(0)).getNext());
					itemLLVTemp.setT(timeNext);
					itemLLVTemp.setD(distanceNext);
					itemLLVTemp.setP(priceNext);
					itemLLVTemp.setPrevS(LVTCur.getS());
					itemLLVTemp.setR((dataNext.get(0)).getRoute());
					itemLLVTemp.setDw(LVTCur.getDw());
					
					LLVTemp.insert(itemLLVTemp, priority);
					
					dataNext.remove(0);
				}
			}
			if(maxwalk > 0){
				ArrayList<NearbyConnectionDTO> dataNear = new ArrayList<NearbyConnectionDTO>();
				dataNear = NodeNearbyConnection.get(LVTCur.getS());
				if(dataNear != null){
					while(dataNear.size() > 0){
						if(minwalk >= (dataNear.get(0)).getDistance()){
							int walknext = 0;
							int priceNext = 0;
							int timeNext = 0;
							int distanceNext = 0;
							walknext = LVTCur.getDw() + (dataNear.get(0)).getDistance();
							if(walknext <= maxwalk){
								priceNext = LVTCur.getP();
								distanceNext = (dataNear.get(0)).getDistance() + LVTCur.getD();
								timeNext = timeChangeRoute + LVTCur.getT() + 
										(3600*((dataNear.get(0)).getDistance())) / (velocityWalk*1000);
								
								LabelDTO itemLLVTemp = new LabelDTO();
								
								itemLLVTemp.setS((dataNear.get(0)).getNearby());
								itemLLVTemp.setT(timeNext);
								itemLLVTemp.setD(distanceNext);
								itemLLVTemp.setP(priceNext);
								itemLLVTemp.setPrevS(LVTCur.getS());
								itemLLVTemp.setR(0);
								itemLLVTemp.setDw(walknext);
								
								LLVTemp.insert(itemLLVTemp, priority);
							}
						}
						dataNear.remove(0);
					}
				}
			}
			// set for loop next
			LabelDTO labelTemp = new LabelDTO();
			labelTemp = LLVTemp.getMinLLVTemp();
			// not exist path between connection
			if (labelTemp == null) {
				findShortPath = false;
				break;
			}
			// set value label vertex current
			LVTCur.setS(labelTemp.getS());
			LVTCur.setT(labelTemp.getT());
			LVTCur.setD(labelTemp.getD());
			LVTCur.setP(labelTemp.getP());
			LVTCur.setPrevS(labelTemp.getPrevS());
			LVTCur.setR(labelTemp.getR());
			LVTCur.setDw(labelTemp.getDw());
			// add list label vertex per
			setLLVPer(labelTemp.getS(), labelTemp.getT(), labelTemp.getD(),
					labelTemp.getP(), labelTemp.getPrevS(), labelTemp.getR(),
					labelTemp.getDw());
			// remove minimum label vertex temporary
			LLVTemp.removeMin(priority);
			// condition stop algorithm
			if ((LVTCur.getS()).equals(arr)) {
				findShortPath = true;
				break;
			}
		}

		if (!findShortPath) {
			LLVPer = null;
		} else {
			String staPrev = (LLVPer.get(LLVPer.size() - 1)).getPrevS();
			for(int i = LLVPer.size() - 2; i >= 0; i--){
				if(staPrev.equals((LLVPer.get(i)).getS()))
				{
					staPrev = (LLVPer.get(i)).getPrevS();
				}
				else
				{
					LLVPer.remove(i);
				}
			}
		}
		return LLVPer;
	}

	public void setLLVPer(String s, int t, int d, int p, String prevS, int r,
			int dw) {
		boolean existLLVPer = false;
		if (LLVPer.size() > 0) {
			for (int i = 0; i < LLVPer.size(); i++) {
				if (s == (LLVPer.get(i)).getS()) {
					existLLVPer = true;
					break;
				}
			}
		}
		if (!existLLVPer) {
			LabelDTO itemLLVPer = new LabelDTO();
			itemLLVPer.setS(s);
			itemLLVPer.setT(t);
			itemLLVPer.setD(d);
			itemLLVPer.setP(p);
			itemLLVPer.setPrevS(prevS);
			itemLLVPer.setR(r);
			itemLLVPer.setDw(dw);
			LLVPer.add(itemLLVPer);
		}
	}
}